using System.Collections.Generic;
using RootMotion.FinalIK;
using UnityEngine;

public class KineticPlan : MonoBehaviour
{
	public struct TransformState
	{
		public Vector3 position;

		public Quaternion rotation;

		public float duration;
	}

	public struct SearchParams
	{
		public Vector3 startPos;

		public Quaternion startRot;

		public Vector3 endPos;

		public int maxDepth;

		public HitAnimationInfo hitAnimation;

		public static SearchParams FromStartToEndPos(Vector3 startPos, Vector3 endPos, Quaternion startRot, HitAnimationInfo hitAnimation)
		{
			SearchParams result = default(SearchParams);
			result.startPos = startPos;
			result.endPos = endPos;
			result.startRot = startRot;
			result.maxDepth = 5;
			result.hitAnimation = hitAnimation;
			return result;
		}
	}

	public struct AnimSearchInfo
	{
		public float maxDistanceInDesiredDirection;

		public MoveAnimationInfo info;
	}

	public class AnimSearchSolution
	{
		public Vector3 startPosition;

		public Quaternion startRotation;

		public Vector3 positionChange;

		public Vector3 desiredPositionChange;

		public FloatRange xAdjustRange;

		public FloatRange zAdjustRange;

		public int steps;

		public List<MoveAnimationInfo> animList = new List<MoveAnimationInfo>();

		public float totalDuration;

		public Vector3 endPosition
		{
			get
			{
				return startPosition + startRotation * (positionChange + adjust);
			}
		}

		public float xAdjust
		{
			get
			{
				Vector3 vector = desiredPositionChange - positionChange;
				return xAdjustRange.InverseLerpZeroCenter(vector.x);
			}
		}

		public float zAdjust
		{
			get
			{
				Vector3 vector = desiredPositionChange - positionChange;
				return zAdjustRange.InverseLerpZeroCenter(vector.z);
			}
		}

		public Vector3 adjust
		{
			get
			{
				return Vector3.right * xAdjustRange.LerpMinMax(xAdjust) + Vector3.forward * zAdjustRange.LerpMinMax(zAdjust);
			}
		}

		public float penalty
		{
			get
			{
				Vector3 error = GetError();
				return Mathf.Abs(error.x) + Mathf.Abs(error.z);
			}
		}

		public string name
		{
			get
			{
				if (animList.Count == 0)
				{
					return "Empty";
				}
				return animList[animList.Count - 1].animatorStateName;
			}
		}

		public void AddSegment(MoveAnimationInfo segment)
		{
			positionChange += segment.positionChange;
			xAdjustRange.Add(segment.xAdjustRange);
			zAdjustRange.Add(segment.zAdjustRange);
			totalDuration += segment.clipLength;
			animList.Add(segment);
		}

		public void RemoveLastSegment()
		{
			if (animList.Count != 0)
			{
				MoveAnimationInfo moveAnimationInfo = animList[animList.Count - 1];
				positionChange -= moveAnimationInfo.positionChange;
				totalDuration -= moveAnimationInfo.clipLength;
				xAdjustRange.Sub(moveAnimationInfo.xAdjustRange);
				zAdjustRange.Sub(moveAnimationInfo.zAdjustRange);
				animList.RemoveAt(animList.Count - 1);
			}
		}

		public Vector3 GetError()
		{
			return desiredPositionChange - (positionChange + adjust);
		}

		public void CloneFromSolutionIfBetter(AnimSearchSolution sol)
		{
			if (sol.penalty < penalty)
			{
				CloneFromSolution(sol);
			}
		}

		public void CloneFromSolution(AnimSearchSolution sol)
		{
			positionChange = sol.positionChange;
			desiredPositionChange = sol.desiredPositionChange;
			xAdjustRange = sol.xAdjustRange;
			zAdjustRange = sol.zAdjustRange;
			animList.Clear();
			steps = sol.steps;
			startPosition = sol.startPosition;
			startRotation = sol.startRotation;
			totalDuration = sol.totalDuration;
			foreach (MoveAnimationInfo anim in sol.animList)
			{
				animList.Add(anim);
			}
		}

		public bool GetIsHit()
		{
			return positionChange.x + xAdjustRange.min <= desiredPositionChange.x && positionChange.x + xAdjustRange.max >= desiredPositionChange.x && positionChange.z + zAdjustRange.min <= desiredPositionChange.z && positionChange.z + zAdjustRange.max >= desiredPositionChange.z;
		}

		public bool GetIsOvershoot()
		{
			return (positionChange + adjust).magnitude > desiredPositionChange.magnitude;
		}
	}

	public struct HitPoint
	{
		public FlightSequence.FlightPlanStage stage;

		public float maxTime;

		public float minReachFlightTime;

		public Vector3 minReachPosition;

		public float maxReachFlightTime;

		public Vector3 maxReachPosition;

		public Vector3 maxPosition;

		public bool foundHitPosition;

		public Vector3 hitAnimationStartPosition;

		public float speedToPosition;

		public float flightTimeWhenHit;

		public float minApproachOptional;
	}

	private List<KineticPlanElement> kineticPlan = new List<KineticPlanElement>();

	public bool dontMove;

	protected Transform _cachedTransform;

	public TableTennisMatchController match;

	protected Animator _cachedAnimator;

	public Transform cachedTransform
	{
		get
		{
			if (_cachedTransform == null)
			{
				_cachedTransform = base.transform;
			}
			return _cachedTransform;
		}
		set
		{
			_cachedTransform = value;
		}
	}

	public FullBodyBipedIK ik
	{
		get
		{
			return cachedTransform.GetComponent<FullBodyBipedIK>();
		}
	}

	public Animator cachedAnimator
	{
		get
		{
			if (_cachedAnimator == null)
			{
				_cachedAnimator = GetComponent<Animator>();
			}
			return _cachedAnimator;
		}
	}

	public KineticPlanElement activeElement
	{
		get
		{
			if (kineticPlan.Count == 0)
			{
				return null;
			}
			return kineticPlan[0];
		}
	}

	public int Count
	{
		get
		{
			return kineticPlan.Count;
		}
	}

	public int indexOfElementOfType<T>() where T : class
	{
		int num = 0;
		foreach (KineticPlanElement item in kineticPlan)
		{
			T val = item as T;
			if (val != null)
			{
				return num;
			}
			num++;
		}
		return -1;
	}

	public T GetFirstElementOfType<T>() where T : class
	{
		int num = indexOfElementOfType<T>();
		if (num < 0)
		{
			return (T)null;
		}
		return kineticPlan[num] as T;
	}

	public void AddElement(KineticPlanElement element)
	{
		kineticPlan.Add(element);
	}

	public void CancelAllPendingElements(int cancelFrom = 1)
	{
		if (kineticPlan.Count > 1)
		{
			kineticPlan.RemoveRange(cancelFrom, kineticPlan.Count - 1);
		}
	}

	public void CancelAll(bool goToIdle = true)
	{
		kineticPlan.Clear();
		cachedAnimator.speed = 1f;
		GoToIdle();
	}

	protected void GoToIdle()
	{
		cachedAnimator.SetFloat("SpeedX", 0f);
		cachedAnimator.SetFloat("SpeedY", 0f);
		cachedAnimator.CrossFade("Idle", 0.1f);
	}

	public TransformState GetTransformStateAfterAllAnimationsFinish()
	{
		TransformState transformState = default(TransformState);
		if (activeElement == null)
		{
			transformState.position = cachedTransform.position;
			transformState.rotation = cachedTransform.rotation;
			return transformState;
		}
		float num = 0f;
		foreach (KineticPlanElement item in kineticPlan)
		{
			transformState = item.GetEndState(transformState);
			num += item.durationTillEnd;
		}
		transformState.duration = num;
		return transformState;
	}

	private void Update()
	{
		if (activeElement == null)
		{
			return;
		}
		if (activeElement.isStarted && !activeElement.isActive)
		{
			KineticPlanElement kineticPlanElement = activeElement;
			kineticPlan.RemoveAt(0);
			if (kineticPlan.Count == 0)
			{
				cachedAnimator.speed = 1f;
				if (kineticPlanElement.continueWithIdle)
				{
					GoToIdle();
				}
				if (ik != null)
				{
					ik.enabled = false;
				}
				return;
			}
		}
		if (!activeElement.isStarted)
		{
			activeElement.OnStart(cachedTransform);
		}
	}

	private void OnAnimatorMove()
	{
		if (activeElement != null && !dontMove)
		{
			activeElement.OnAnimatorMove();
		}
	}

	private void LateUpdate()
	{
		if (activeElement != null)
		{
			activeElement.OnLateUpdate();
		}
	}

	private void OnAnimatorIK()
	{
		if (!(cachedAnimator == null) && !(match == null))
		{
			PhysicsBall ball = match.ball;
			if (!(ball == null))
			{
			}
		}
	}

	public static float FindMaxDistanceInDesiredDirection(MoveAnimationInfo info, Vector3 desiredDirection)
	{
		return FindMaxDistanceInDesiredDirection(info.positionChange, info.xAdjustRange, info.zAdjustRange, desiredDirection);
	}

	public static float FindMaxDistanceInDesiredDirection(Vector3 positionChange, FloatRange xAdjustRange, FloatRange zAdjustRange, Vector3 desiredDirection)
	{
		return Mathf.Max(Vector3.Dot(desiredDirection, positionChange + new Vector3(xAdjustRange.LerpMinMax(-1f), 0f, zAdjustRange.LerpMinMax(-1f))), Vector3.Dot(desiredDirection, positionChange + new Vector3(xAdjustRange.LerpMinMax(1f), 0f, zAdjustRange.LerpMinMax(-1f))), Vector3.Dot(desiredDirection, positionChange + new Vector3(xAdjustRange.LerpMinMax(1f), 0f, zAdjustRange.LerpMinMax(1f))), Vector3.Dot(desiredDirection, positionChange + new Vector3(xAdjustRange.LerpMinMax(-1f), 0f, zAdjustRange.LerpMinMax(1f))));
	}

	public static float FindMinDistanceInDesiredDirection(Vector3 positionChange, FloatRange xAdjustRange, FloatRange zAdjustRange, Vector3 desiredDirection)
	{
		return Mathf.Min(Vector3.Dot(desiredDirection, positionChange + new Vector3(xAdjustRange.LerpMinMax(-1f), 0f, zAdjustRange.LerpMinMax(-1f))), Vector3.Dot(desiredDirection, positionChange + new Vector3(xAdjustRange.LerpMinMax(1f), 0f, zAdjustRange.LerpMinMax(-1f))), Vector3.Dot(desiredDirection, positionChange + new Vector3(xAdjustRange.LerpMinMax(1f), 0f, zAdjustRange.LerpMinMax(1f))), Vector3.Dot(desiredDirection, positionChange + new Vector3(xAdjustRange.LerpMinMax(-1f), 0f, zAdjustRange.LerpMinMax(1f))));
	}

	public void FillListWithMoveAnimsGoingInDirection(List<AnimSearchInfo> animsToSearch, Vector3 desiredDirection)
	{
		desiredDirection.Normalize();
		foreach (MoveAnimationInfo moveAnimation in ScriptableObjectSingleton<KineticAnimationInfoDB>.instance.moveAnimations)
		{
			float num = FindMaxDistanceInDesiredDirection(moveAnimation, desiredDirection);
			if (!(num <= 0f) && !(Vector3.Dot(moveAnimation.positionChange, desiredDirection) < 0f))
			{
				AnimSearchInfo item = default(AnimSearchInfo);
				item.info = moveAnimation;
				item.maxDistanceInDesiredDirection = num;
				animsToSearch.Add(item);
			}
		}
	}

	public AnimSearchSolution FindPathToGetToPosition(SearchParams p)
	{
		Vector3 desiredPositionChange = Quaternion.Inverse(p.startRot) * (p.endPos - p.startPos).OnGround();
		Vector3 normalized = desiredPositionChange.normalized;
		AnimSearchSolution animSearchSolution = new AnimSearchSolution();
		animSearchSolution.desiredPositionChange = desiredPositionChange;
		animSearchSolution.startRotation = p.startRot;
		animSearchSolution.startPosition = p.startPos;
		if (p.hitAnimation != null)
		{
			animSearchSolution.xAdjustRange.Add(p.hitAnimation.xAdjustRange);
			animSearchSolution.zAdjustRange.Add(p.hitAnimation.zAdjustRange);
		}
		float num = 0.2f;
		if (desiredPositionChange.magnitude < num)
		{
			return animSearchSolution;
		}
		List<AnimSearchInfo> list = new List<AnimSearchInfo>();
		FillListWithMoveAnimsGoingInDirection(list, normalized);
		list.Sort((AnimSearchInfo info1, AnimSearchInfo info2) => -info1.maxDistanceInDesiredDirection.CompareTo(info2.maxDistanceInDesiredDirection));
		AnimSearchSolution animSearchSolution2 = new AnimSearchSolution();
		animSearchSolution2.CloneFromSolution(animSearchSolution);
		SearchSolutionTree(animSearchSolution, animSearchSolution2, list, 0, desiredPositionChange, 0, p.maxDepth);
		animSearchSolution2.steps = animSearchSolution.steps;
		return animSearchSolution2;
	}

	private bool SearchSolutionTree(AnimSearchSolution solution, AnimSearchSolution bestSolution, List<AnimSearchInfo> animsToSearch, int minIndexToStart, Vector3 desiredPositionChange, int depth, int maxDepth)
	{
		solution.steps++;
		if (solution.GetIsHit())
		{
			bestSolution.CloneFromSolution(solution);
			return true;
		}
		if (solution.GetIsOvershoot())
		{
			return false;
		}
		if (depth > maxDepth)
		{
			return false;
		}
		bestSolution.CloneFromSolutionIfBetter(solution);
		for (int i = minIndexToStart; i < animsToSearch.Count; i++)
		{
			solution.AddSegment(animsToSearch[i].info);
			if (SearchSolutionTree(solution, bestSolution, animsToSearch, i, desiredPositionChange, depth + 1, maxDepth))
			{
				return true;
			}
			solution.RemoveLastSegment();
		}
		return false;
	}

	public static HitPoint FindHitPoint(PhysicsBall ball, float mySideOfTheTable, float symDeltaTime, HitAnimationInfo hitInfo)
	{
		HitPoint result = default(HitPoint);
		FlightSequence flightSequence = ball.flightSequence;
		FlightSequence.FlightPlanStage flightPlanStage = (result.stage = flightSequence.GetStageThatStartsFromTableSide(Mathf.Sign(mySideOfTheTable)));
		if (flightPlanStage == null)
		{
			return result;
		}
		BallFlight flight = flightPlanStage.flight;
		flight.SetInitialConditions(flightPlanStage.startParams, null);
		float num = 0f;
		float num2 = 0f;
		float num3 = 0.05f;
		Quaternion quaternion = Quaternion.LookRotation(Vector3.forward * Mathf.Sign(0f - mySideOfTheTable));
		Vector3 vector = flight.PositionAt(ball.flightSequence.flightTime);
		for (float num4 = 0f; num4 < flightPlanStage.duration; num4 += symDeltaTime)
		{
			Vector3 vector2 = flight.PositionAt(num4);
			float num5 = result.stage.startTime + num4 - ball.flightSequence.flightTime;
			if (!(num5 < num3) && !(vector2.y < hitInfo.hitPosition.y - 0.07f) && !(vector2.y > hitInfo.hitPosition.y + 0.07f) && (!(Mathf.Abs(vector2.z) > Table.halfLength * 1.25f) || !(Mathf.Abs(vector2.z) > Mathf.Abs(vector.z) + 0.5f)) && vector2.y >= num2)
			{
				Vector3 hitAnimationStartPosition = (vector2 - quaternion * hitInfo.hitPosition).OnGround();
				if ((double)Mathf.Abs(hitAnimationStartPosition.z) >= (double)Table.halfLength + 0.1)
				{
					num = num4;
					num2 = vector2.y;
					result.maxTime = num;
					result.maxPosition = vector2;
					result.hitAnimationStartPosition = hitAnimationStartPosition;
					result.foundHitPosition = true;
				}
			}
		}
		return result;
	}

	public static HitPoint FindHitPointMinimizeZ(PhysicsBall ball, float mySideOfTheTable, float symDeltaTime, HitAnimationInfo hitInfo, Vector3 playerPosition, float maxHitAnimatorSpeed = 3f)
	{
		HitPoint result = default(HitPoint);
		FlightSequence flightSequence = ball.flightSequence;
		FlightSequence.FlightPlanStage flightPlanStage = (result.stage = flightSequence.GetStageThatStartsFromTableSide(Mathf.Sign(mySideOfTheTable)));
		if (flightPlanStage == null)
		{
			return result;
		}
		BallFlight flight = flightPlanStage.flight;
		flight.SetInitialConditions(flightPlanStage.startParams, null);
		float num = 0f;
		float num2 = 0f;
		float num3 = hitInfo.hitTime / maxHitAnimatorSpeed;
		Quaternion quaternion = Quaternion.LookRotation(Vector3.forward * Mathf.Sign(0f - mySideOfTheTable));
		Vector3 vector = flight.PositionAt(ball.flightSequence.flightTime);
		float num4 = Mathf.Abs(Table.halfLength);
		float num5 = 0.01f;
		float num6 = 10000f;
		float num7 = Mathf.Max(0f, ball.flightSequence.flightTime + num3 - result.stage.startTime);
		for (float num8 = num7; num8 < flightPlanStage.duration; num8 += symDeltaTime)
		{
			Vector3 vector2 = flight.PositionAt(num8);
			float num9 = result.stage.startTime + num8 - ball.flightSequence.flightTime;
			if (vector2.y < hitInfo.hitPosition.y + hitInfo.yHitAdjustRange.min || vector2.y > hitInfo.hitPosition.y + hitInfo.yHitAdjustRange.max)
			{
				continue;
			}
			float f = Mathf.Abs(vector2.z + Mathf.Sign(playerPosition.z) * hitInfo.hitPosition.z) - Mathf.Abs(playerPosition.z);
			if (Mathf.Abs(f) <= num6)
			{
				Vector3 hitAnimationStartPosition = (vector2 - quaternion * hitInfo.hitPosition).OnGround();
				if (Mathf.Abs(hitAnimationStartPosition.z) >= Table.halfLength + hitInfo.minDistanceFromTable)
				{
					num = num8;
					num2 = vector2.y;
					num6 = Mathf.Abs(f);
					result.maxTime = num;
					result.maxPosition = vector2;
					result.hitAnimationStartPosition = hitAnimationStartPosition;
					result.foundHitPosition = true;
				}
			}
		}
		return result;
	}

	public static HitPoint FindHitPointMinimizeZIncludeSpeed(PhysicsBall ball, float mySideOfTheTable, float symDeltaTime, HitAnimationInfo hitInfo, Vector3 playerPosition, float maxHitAnimatorSpeed, float maxSpeed, float maxJumpSpeed, FloatRange xAdjustRange, FloatRange zAdjustRange, bool debug = false)
	{
		HitPoint result = default(HitPoint);
		FlightSequence flightSequence = ball.flightSequence;
		FlightSequence.FlightPlanStage flightPlanStage = (result.stage = flightSequence.GetStageThatStartsFromTableSide(Mathf.Sign(mySideOfTheTable)));
		if (flightPlanStage == null || hitInfo == null)
		{
			return result;
		}
		BallFlight flight = flightPlanStage.flight;
		flight.SetInitialConditions(flightPlanStage.startParams, null);
		float num = 0f;
		float num2 = 0f;
		float num3 = hitInfo.hitTime / maxHitAnimatorSpeed;
		Quaternion quaternion = Quaternion.LookRotation(Vector3.forward * Mathf.Sign(0f - mySideOfTheTable));
		Vector3 vector = flight.PositionAt(ball.flightSequence.flightTime);
		float num4 = Mathf.Abs(Table.halfLength);
		float num5 = 0.01f;
		float num6 = 10000f;
		float num7 = 10000f;
		float num8 = 0f;
		float num9 = Mathf.Max(0f, ball.flightSequence.flightTime + num3 - result.stage.startTime) + 0.05f;
		int num10 = Random.Range(0, 10000);
		for (float num11 = num9; num11 < flightPlanStage.duration; num11 += symDeltaTime)
		{
			Vector3 vector2 = flight.PositionAt(num11);
			float num12 = result.stage.startTime + num11 - ball.flightSequence.flightTime;
			if (vector2.y < hitInfo.hitPosition.y + hitInfo.yHitAdjustRange.min || vector2.y > hitInfo.hitPosition.y + hitInfo.yHitAdjustRange.max)
			{
				continue;
			}
			float f = Mathf.Abs(vector2.z + Mathf.Sign(playerPosition.z) * hitInfo.hitPosition.z) - Mathf.Abs(playerPosition.z);
			if (!(Mathf.Abs(f) <= num6) && !(num11 <= num7) && !(num11 >= num8))
			{
				continue;
			}
			float num13 = 0f;
			Vector3 vector3 = (vector2 - quaternion * hitInfo.hitPosition).OnGround();
			Vector3 vector4 = (vector3 - playerPosition).OnGround();
			float num14 = 0f;
			if (!xAdjustRange.isIncluding(vector4.x) || !zAdjustRange.isIncluding(vector4.z))
			{
				num13 = vector4.magnitude / num12;
			}
			else
			{
				num14 = vector4.magnitude / num12;
			}
			if (debug)
			{
				GGDebug.DebugLog("jump speed " + num14 + " speed " + num13 + " dx " + vector4.x + " dz " + vector4.z + " distance " + vector4.magnitude);
			}
			if (Mathf.Abs(vector3.z) >= Table.halfLength + hitInfo.minDistanceFromTable && num13 <= maxSpeed && num14 <= maxJumpSpeed)
			{
				if (Mathf.Abs(f) <= num6)
				{
					num = num11;
					num2 = vector2.y;
					num6 = Mathf.Abs(f);
					result.maxTime = num;
					result.maxPosition = vector2;
					result.hitAnimationStartPosition = vector3;
					result.foundHitPosition = true;
					result.speedToPosition = num13;
					result.flightTimeWhenHit = flightPlanStage.startTime + num;
				}
				if (num11 <= num7)
				{
					num7 = num11;
					result.minReachFlightTime = num7 + flightPlanStage.startTime;
					result.minReachPosition = vector3;
				}
				if (num11 >= num8)
				{
					num8 = num11;
					result.maxReachFlightTime = num8 + flightPlanStage.startTime;
					result.maxReachPosition = vector3;
				}
			}
		}
		return result;
	}

	public static HitPoint FindClosestPointMinimizeZIncludeSpeed(PhysicsBall ball, float mySideOfTheTable, float symDeltaTime, HitAnimationInfo hitInfo, Vector3 playerPosition, float maxHitAnimatorSpeed, float maxSpeed, float maxJumpSpeed)
	{
		HitPoint result = default(HitPoint);
		result.hitAnimationStartPosition = playerPosition;
		FlightSequence flightSequence = ball.flightSequence;
		FlightSequence.FlightPlanStage flightPlanStage = (result.stage = flightSequence.GetStageThatStartsFromTableSide(Mathf.Sign(mySideOfTheTable)));
		if (flightPlanStage == null || hitInfo == null)
		{
			return result;
		}
		BallFlight flight = flightPlanStage.flight;
		flight.SetInitialConditions(flightPlanStage.startParams, null);
		float num = 0f;
		float num2 = 0f;
		float num3 = hitInfo.hitTime / maxHitAnimatorSpeed;
		Quaternion quaternion = Quaternion.LookRotation(Vector3.forward * Mathf.Sign(0f - mySideOfTheTable));
		Vector3 vector = flight.PositionAt(ball.flightSequence.flightTime);
		float num4 = Mathf.Abs(Table.halfLength);
		float num5 = 0.01f;
		float num6 = 10000f;
		float num7 = 10000f;
		float num8 = 0f;
		float num9 = 10000f;
		float num10 = Mathf.Max(0f, ball.flightSequence.flightTime + num3 - result.stage.startTime);
		for (float num11 = num10; num11 < flightPlanStage.duration; num11 += symDeltaTime)
		{
			Vector3 vector2 = flight.PositionAt(num11);
			Vector3 vector3 = vector2;
			float num12 = result.stage.startTime + num11 - ball.flightSequence.flightTime;
			if (vector3.y < hitInfo.hitPosition.y + hitInfo.yHitAdjustRange.min)
			{
				vector3.y = hitInfo.hitPosition.y + hitInfo.yHitAdjustRange.min;
			}
			if (vector3.y > hitInfo.hitPosition.y + hitInfo.yHitAdjustRange.max)
			{
				vector3.y = hitInfo.hitPosition.y + hitInfo.yHitAdjustRange.max;
			}
			float f = Mathf.Abs(vector3.z + Mathf.Sign(playerPosition.z) * hitInfo.hitPosition.z) - Mathf.Abs(playerPosition.z);
			if (!(Mathf.Abs(f) <= num6) && !(num11 <= num7) && !(num11 >= num8))
			{
				continue;
			}
			float a = 0f;
			Vector3 vector4 = (vector3 - quaternion * hitInfo.hitPosition).OnGround();
			Vector3 vector5 = vector4 - playerPosition;
			float num13 = 0f;
			if (!hitInfo.xAdjustRange.isIncluding(vector5.x) || !hitInfo.zAdjustRange.isIncluding(vector5.x))
			{
				a = vector5.magnitude / num12;
			}
			else
			{
				num13 = vector5.magnitude / num12;
			}
			if (Mathf.Abs(vector4.z) >= Table.halfLength + hitInfo.minDistanceFromTable)
			{
				a = Mathf.Min(a, maxSpeed);
				vector4 = playerPosition + vector5.normalized * a * num12;
				vector3.x = vector4.x + quaternion.x * hitInfo.hitPosition.x;
				vector3.z = vector4.z + quaternion.x * hitInfo.hitPosition.z;
				if (Mathf.Abs(f) <= num6 && (vector2 - vector3).magnitude < num9)
				{
					num = num11;
					num2 = vector3.y;
					num6 = Mathf.Abs(f);
					num9 = (result.minApproachOptional = (vector2 - vector3).magnitude);
					result.maxTime = num;
					result.speedToPosition = a;
					result.maxPosition = vector3;
					result.hitAnimationStartPosition = (vector2 - quaternion * hitInfo.hitPosition).OnGround();
					result.foundHitPosition = false;
					result.flightTimeWhenHit = flightPlanStage.startTime + num;
				}
				if (num11 <= num7)
				{
					num7 = num11;
					result.minReachFlightTime = num7 + flightPlanStage.startTime;
					result.minReachPosition = vector4;
				}
				if (num11 >= num8)
				{
					num8 = num11;
					result.maxReachFlightTime = num8 + flightPlanStage.startTime;
					result.maxReachPosition = vector4;
				}
			}
		}
		return result;
	}

	public static HitPoint FindHitPointMaximizeReacheabilityIncludeSpeed(PhysicsBall ball, float mySideOfTheTable, float symDeltaTime, HitAnimationInfo hitInfo, Vector3 playerPosition, float maxHitAnimatorSpeed, float maxSpeed, float maxJumpSpeed)
	{
		HitPoint result = default(HitPoint);
		FlightSequence flightSequence = ball.flightSequence;
		FlightSequence.FlightPlanStage flightPlanStage = (result.stage = flightSequence.GetStageThatStartsFromTableSide(Mathf.Sign(mySideOfTheTable)));
		if (flightPlanStage == null || hitInfo == null)
		{
			return result;
		}
		BallFlight flight = flightPlanStage.flight;
		flight.SetInitialConditions(flightPlanStage.startParams, null);
		float num = 0f;
		float num2 = 0f;
		float num3 = hitInfo.hitTime / maxHitAnimatorSpeed;
		Quaternion quaternion = Quaternion.LookRotation(Vector3.forward * Mathf.Sign(0f - mySideOfTheTable));
		Vector3 vector = flight.PositionAt(ball.flightSequence.flightTime);
		float num4 = Mathf.Abs(Table.halfLength);
		float num5 = 0.01f;
		float num6 = 10000f;
		float num7 = Mathf.Max(0f, ball.flightSequence.flightTime + num3 - result.stage.startTime);
		for (float num8 = num7; num8 < flightPlanStage.duration; num8 += symDeltaTime)
		{
			Vector3 vector2 = flight.PositionAt(num8);
			float num9 = result.stage.startTime + num8 - ball.flightSequence.flightTime;
			if (vector2.y < hitInfo.hitPosition.y + hitInfo.yHitAdjustRange.min || vector2.y > hitInfo.hitPosition.y + hitInfo.yHitAdjustRange.max)
			{
				continue;
			}
			float f = Mathf.Abs(vector2.z + Mathf.Sign(playerPosition.z) * hitInfo.hitPosition.z) - Mathf.Abs(playerPosition.z);
			if (Mathf.Abs(f) <= num6)
			{
				float num10 = 0f;
				Vector3 vector3 = (vector2 - quaternion * hitInfo.hitPosition).OnGround();
				Vector3 vector4 = vector3 - playerPosition;
				float num11 = 0f;
				if (!hitInfo.xAdjustRange.isIncluding(vector4.x) || !hitInfo.zAdjustRange.isIncluding(vector4.x))
				{
					num10 = vector4.magnitude / num9;
				}
				else
				{
					num11 = vector4.magnitude / num9;
				}
				if (Mathf.Abs(vector3.z) >= Table.halfLength + hitInfo.minDistanceFromTable && num10 <= maxSpeed && num11 <= maxJumpSpeed)
				{
					num = num8;
					num2 = vector2.y;
					num6 = Mathf.Abs(f);
					result.maxTime = num;
					result.maxPosition = vector2;
					result.hitAnimationStartPosition = vector3;
					result.foundHitPosition = true;
					result.speedToPosition = num10;
					result.flightTimeWhenHit = flightPlanStage.startTime + num;
				}
			}
		}
		return result;
	}

	public static HitPoint FindHitPointClosestToPlayer(PhysicsBall ball, float mySideOfTheTable, float symDeltaTime, HitAnimationInfo hitInfo, Transform player)
	{
		HitPoint result = default(HitPoint);
		FlightSequence flightSequence = ball.flightSequence;
		FlightSequence.FlightPlanStage flightPlanStage = (result.stage = flightSequence.GetStageThatStartsFromTableSide(Mathf.Sign(mySideOfTheTable)));
		if (flightPlanStage == null)
		{
			return result;
		}
		BallFlight flight = flightPlanStage.flight;
		flight.SetInitialConditions(flightPlanStage.startParams, null);
		float num = 0f;
		float num2 = 0f;
		float num3 = 0.1f;
		Quaternion quaternion = Quaternion.LookRotation(Vector3.forward * Mathf.Sign(0f - mySideOfTheTable));
		Vector3 vector = flight.PositionAt(ball.flightSequence.flightTime);
		float a = Mathf.Abs(Table.halfLength + 0.2f);
		float num4 = 0.01f;
		float num5 = 10000f;
		float hitTime = hitInfo.hitTime;
		for (float num6 = 0f; num6 < flightPlanStage.duration; num6 += symDeltaTime)
		{
			Vector3 vector2 = flight.PositionAt(num6);
			float num7 = result.stage.startTime + num6 - ball.flightSequence.flightTime;
			if (num7 < num3)
			{
				a = Mathf.Max(a, Mathf.Abs(vector2.z));
				num4 = 0.5f;
			}
			else
			{
				if (vector2.y < hitInfo.hitPosition.y + hitInfo.yHitAdjustRange.min || vector2.y > hitInfo.hitPosition.y + hitInfo.yHitAdjustRange.max)
				{
					continue;
				}
				float num8 = Mathf.Abs(vector2.z + Mathf.Sign(player.position.z) * hitInfo.hitPosition.z) - Mathf.Abs(player.position.z);
				float f = num6 - hitTime;
				if (Mathf.Abs(f) <= num5)
				{
					Vector3 hitAnimationStartPosition = (vector2 - quaternion * hitInfo.hitPosition).OnGround();
					if (Mathf.Abs(hitAnimationStartPosition.z) >= Table.halfLength + hitInfo.minDistanceFromTable)
					{
						num = num6;
						num2 = vector2.y;
						num5 = Mathf.Abs(f);
						result.maxTime = num;
						result.maxPosition = vector2;
						result.hitAnimationStartPosition = hitAnimationStartPosition;
						result.foundHitPosition = true;
					}
				}
			}
		}
		return result;
	}

	public static HitPoint FindHitPoint(PhysicsBall ball, float mySideOfTheTable, float symDeltaTime, HitAnimationInfo hitInfo, Transform player, float maxVelocity)
	{
		HitPoint result = default(HitPoint);
		FlightSequence flightSequence = ball.flightSequence;
		FlightSequence.FlightPlanStage flightPlanStage = (result.stage = flightSequence.GetStageThatStartsFromTableSide(Mathf.Sign(mySideOfTheTable)));
		if (flightPlanStage == null)
		{
			return result;
		}
		BallFlight flight = flightPlanStage.flight;
		flight.SetInitialConditions(flightPlanStage.startParams, null);
		float num = 0f;
		float num2 = 0f;
		float num3 = 0.1f;
		Quaternion quaternion = Quaternion.LookRotation(Vector3.forward * Mathf.Sign(0f - mySideOfTheTable));
		Vector3 vector = flight.PositionAt(ball.flightSequence.flightTime);
		float a = Mathf.Abs(Table.halfLength + 0.2f);
		float num4 = 0.01f;
		float num5 = 1000f;
		for (float num6 = 0f; num6 < flightPlanStage.duration; num6 += symDeltaTime)
		{
			Vector3 vector2 = flight.PositionAt(num6);
			float num7 = result.stage.startTime + num6 - ball.flightSequence.flightTime;
			if (num7 < num3)
			{
				a = Mathf.Max(a, Mathf.Abs(vector2.z));
				num4 = 0.5f;
			}
			else
			{
				if (vector2.y < Table.tabletopy * 0.75f || vector2.y > hitInfo.hitPosition.y + 1.25f)
				{
					continue;
				}
				float num8 = Mathf.Abs(vector2.z + Mathf.Sign(player.position.z) * hitInfo.hitPosition.z) - Mathf.Abs(player.position.z);
				if (num7 < num5)
				{
					Vector3 hitAnimationStartPosition = (vector2 - quaternion * hitInfo.hitPosition).OnGround();
					if ((double)Mathf.Abs(hitAnimationStartPosition.z) >= (double)Table.halfLength + 0.1)
					{
						num = num6;
						num2 = vector2.y;
						num5 = num7;
						result.maxTime = num;
						result.maxPosition = vector2;
						result.hitAnimationStartPosition = hitAnimationStartPosition;
						result.foundHitPosition = true;
					}
				}
			}
		}
		GGDebug.DebugLog("time " + num5);
		return result;
	}
}
